using System;
using System.Collections;


namespace SolarDevices
{
    public class ClassicRegisterTable : RegisterTableBase, IRegisterTable
    {
        readonly Register[] _chargeStateRegister;

        private ModbusTCPDevice _modbusTCPDevice;

        public ClassicRegisterTable()
        {
            _chargeStateRegister = new[]{
                                           new Register { Address = 4115, Label = "Average battery voltage", UnitOfMeasure = "Volts", Conversion = address => U16_OneDec(address)},
                                           new Register { Address = 4116, Label = "PV input voltage", UnitOfMeasure = "Volts", Conversion = address => U16_OneDec(address)},
                                           new Register { Address = 4117, Label = "Average battery current", UnitOfMeasure = "Amps", Conversion = address => U16_OneDec(address)},
                                           new Register { Address = 4118, Label = "Average energy to the battery", UnitOfMeasure = "kWh", Conversion = address => U16_OneDec(address)},
                                           new Register { Address = 4119, Label = "Average power to the battery", UnitOfMeasure = "Watts", Conversion = address => U16(address)},
                                           new Register { Address = 4120, Label = "Battery charge state", UnitOfMeasure = "", Conversion = address => ChargeState(address)},
                                           new Register { Address = 4121, Label = "Average PV inout current", UnitOfMeasure = "Amps", Conversion = address => U16_OneDec(address)},
                                           new Register { Address = 4122, Label = "PV VOC", UnitOfMeasure = "Volts", Conversion = address => U16_OneDec(address)},
                                           new Register { Address = 4125, Label = "Daily amp hours", UnitOfMeasure = "Amp hours", Conversion = address => U16_OneDec(address)},
                                           new Register { Address = 4126, Label = "Total kWhours", UnitOfMeasure = "kWh", Conversion = address => U32_OneDec(address)},
                                           new Register { Address = 4128, Label = "Total Amp hours", UnitOfMeasure = "Amp hours", Conversion = address => U32_OneDec(address)},
                                           new Register { Address = 4130, Label = "Info flag", UnitOfMeasure = "", Conversion = address => Info(address)}

                                       };

            _offset = _chargeStateRegister[0].Address - 1;
            _modbusTCPDevice = ModbusTCPDevice.GetSingleton();
            _modbusTCPDevice.Address = _offset;
            _modbusTCPDevice.Count = _chargeStateRegister[_chargeStateRegister.Length - 1].Address - _offset + 4;
        }

        public void Dispose()
        {
            _modbusTCPDevice.Dispose();
            _modbusTCPDevice = null;
        }


        public void StartPolling()
        {
            _modbusTCPDevice.StartPolling();
        }

        public void AddInverterData(ref ChargeState chargeState)
        {
            return; // not implemented
        }

        public void ReadChargeEvent(ref ChargeEvent ce)
        {
            if (_modbusTCPDevice.Connected == false)
            {
                throw new Exception("No connection");
            }
            var p = Data[4119 - Offset];
            var code = p >> 8;
            switch (code)
            {
                case 0:
                case 10:
                    ce.StateCode = StateCode.Resting;
                    break;
                case 3:
                    ce.StateCode = StateCode.Absorb;
                    break;
                case 4:
                case 6:
                    ce.StateCode = StateCode.Bulk;
                    break;
                case 5:
                    ce.StateCode = StateCode.Float;
                    break;
                case 7:
                case 18:
                    ce.StateCode = StateCode.Equalize;
                    break;
            }
            ce.EnergyToday = U16_OneDec(4117);
        }

        public void ReadInverterEvent(ref ChargeEvent ce)
        {
            return; // not implemented
        }

        public ChargeState ReadChargeState()
        {
            if (!_modbusTCPDevice.Connected)
            {
                var chargeState = new ChargeState
                {
                    Connected = false
                };
                return chargeState; 
            }
            _data = _modbusTCPDevice.GetData();
            if (_data != null)
            {
                var chargeState = new ChargeState
                {
                    BatteryVolts = _chargeStateRegister[0].Text,
                    PvVolts = _chargeStateRegister[1].Text,
                    BatteryAmps = _chargeStateRegister[2].Text,
                    EnergyToday = _chargeStateRegister[3].Text,
                    Watts = _chargeStateRegister[4].Text,
                    State = _chargeStateRegister[5].Text,
                    PvAmps = _chargeStateRegister[6].Text,
                    TotalKwH = _chargeStateRegister[9].Text,
                    ControllerError = _chargeStateRegister[11].Text,
                    Connected = true
                };
                return chargeState;                
            }
            return new ChargeState();
        }

        private string Info(int address)
        {
            UInt32 l = Data[address - Offset + 1];
            l = l << 16;
            return ClassicLookupTables.ParseInfoFlag(l | Data[address - Offset]);
        }

        private string ChargeState(int address)
        {
            var p = Data[address - Offset];
            var n = p >> 8;
            return ClassicLookupTables.LookupBatteryStage(n);
        }

    }
}